import { EventEmitter, Injectable } from '@angular/core';
import { DomService } from './dom.service';
import { MessagerService } from '@farris/ui-messager';
import { FormBasicService } from '../services/form-basic.service';
import { NotifyService } from '@farris/ui-notify';
import { switchMap } from 'rxjs/operators';
import { Observable, of, throwError as observableThrowError } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { DesignerEnvType } from '../entity';
import { FarrisMetadataDto, FarrisMetadataService } from './metadata-service';

/**
 * 新增构件、新增构件方法的服务
 */
@Injectable({
    providedIn: 'root'
})
export class WebCmpBuilderService {

    /** 构件元数据构造数据 */
    public buildInfo: any;

    /** ts代码文件路径 */
    private tsFilePathName: string;

    /** 新增构件方法，并触发打开代码视图 */
    public openCodeViewWithNewMethod = new EventEmitter<any>();

    private hasWebCmp = false;
    private hasWebCmd = false;

    private methodCode: string;
    private methodName: string;

    constructor(
        public domService: DomService,
        public msgService: MessagerService,
        public metadataService: FarrisMetadataService,
        public formBasicService: FormBasicService,
        private notifyService: NotifyService,
        private http: HttpClient,
    ) { }

    public addControllerMethod(methodCode: string, methodName: string) {
        this.methodCode = methodCode;
        this.methodName = methodName;

        this.checkHasController().subscribe((result) => {
            // 若不存在构件，先创建构件
            if (!result) {
                this.createWebMetadata();
            } else {
                if (this.formBasicService.envType === DesignerEnvType.designer) {
                    this.openCodeViewWithNewMethod.emit({ tsFilePathName: this.tsFilePathName, methodCode, methodName });
                } else {
                    this.openCodeViewWithNewMethod.emit(this.tsFilePathName);
                }
            }
        });
    }

    /**
     * 校验当前表单是否已有web构件和命令构件
     */
    private checkHasController(): Observable<boolean> {
        const formInfo = this.formBasicService.formMetaBasicInfo;
        let suffix = '_frm_Controller';
        if (this.formBasicService.envType === DesignerEnvType.mobileDesigner) {
            suffix = '_mfrm_Controller';

        }
        // 默认构件命令为'表单编号_frm_Controller'
        this.buildInfo = {
            code: formInfo.code + suffix,
            name: formInfo.name + suffix,
            namespace: formInfo.nameSpace,
            bizObjId: formInfo.bizobjectID,
            relativePath: formInfo.relativePath,
            extendProperty: { IsCommon: false, FormCode: formInfo.code }
        };
        const webCmpFileName = this.buildInfo.code + '.webcmp';
        const webCmdFileName = this.buildInfo.code + '.webcmd';

        this.tsFilePathName = '/' + this.buildInfo.relativePath + '/' + this.buildInfo.code + '.ts';
        return this.metadataService.validateRepeatName(this.buildInfo.relativePath, webCmpFileName).pipe(
            switchMap(notExsited => {

                this.hasWebCmp = !notExsited;

                // 再检查命令构件是否存在
                return this.metadataService.validateRepeatName(this.buildInfo.relativePath, webCmdFileName);
            }),
            switchMap(notExsited2 => {
                this.hasWebCmd = !notExsited2;
                if (this.hasWebCmd) {
                    // 查询命令构件信息---用于获取命令构件id
                    return this.metadataService.loadMetadata(webCmdFileName, this.buildInfo.relativePath);
                } else {
                    return of(null);
                }
            }),
            switchMap((data: any) => {

                if (this.hasWebCmd && data) {
                    this.buildInfo.webCmdId = data.id;
                }
                return of(this.hasWebCmp && this.hasWebCmd);
            })
        );
    }


    /**
     * 创建构件：先创建web构件，再创建命令构件
     */
    private createWebMetadata() {
        const fileName = this.buildInfo.code + '.webcmp';

        const metadatadto = new FarrisMetadataDto('', this.buildInfo.namespace, this.buildInfo.code, this.buildInfo.name,
            fileName, 'WebComponent', this.buildInfo.bizObjId, this.buildInfo.relativePath, JSON.stringify(this.buildInfo.extendProperty), '', false);

        // 已存在web构件， 只创建命令构件
        if (this.hasWebCmp) {
            this.createWebCommand();
            return;
        }
        // 不存在web构件，先创建web构件
        this.metadataService.initializeMetadataEntity(metadatadto).pipe(
            switchMap(data => {
                data.fileName = metadatadto.fileName;
                const path = this.buildInfo.relativePath + '/';
                const tsFileName = this.buildInfo.code + '.ts';
                const sourcePath = path + tsFileName;
                const webComponent = JSON.parse(data.content) as WebComponentMetadata;
                webComponent.Source = sourcePath.toString();
                data.content = JSON.stringify(webComponent);
                return this.metadataService.createMetadata(data);
            }),
            switchMap(result => {
                if (result.ok) {
                    let url = '/api/dev/main/v1.0/tsfile/create?path=' + this.tsFilePathName;

                    if (this.formBasicService.envType === DesignerEnvType.mobileDesigner) {
                        url = '/api/dev/main/v1.0/tsfile/create/mobile?path=' + this.tsFilePathName;

                    }
                    return this.http.post(url, {});
                } else {
                    this.notifyService.error('Web构件创建失败');
                    return observableThrowError('Web构件创建失败');
                }
            })
        ).subscribe(data => {
            // web构件创建成功，若没有命令构件，则创建命令构件，若已有命令构件，则直接触发打开代码视图
            if (!this.hasWebCmd) {
                this.createWebCommand();
            } else {
                if (this.formBasicService.envType === DesignerEnvType.designer) {
                    this.openCodeViewWithNewMethod.emit({ tsFilePathName: this.tsFilePathName, methodCode: this.methodCode, methodName: this.methodName });
                } else {
                    this.openCodeViewWithNewMethod.emit(this.tsFilePathName);
                }
            }
        });
    }

    /**
     * 创建命令构件
     */
    private createWebCommand() {
        const fileName = this.buildInfo.code + '.webcmd';
        const metadatadto = new FarrisMetadataDto('', this.buildInfo.namespace, this.buildInfo.code, this.buildInfo.name,
            fileName, 'WebCommand', this.buildInfo.bizObjId, this.buildInfo.relativePath, JSON.stringify(this.buildInfo.extendProperty), '', false);

        this.metadataService.initializeMetadataEntity(metadatadto).pipe(
            switchMap(data => {
                data.fileName = metadatadto.fileName;
                this.buildInfo.webCmdId = data.id;
                return this.metadataService.createMetadata(data);
            })
        ).subscribe(result => {
            if (result.ok) {
                if (this.formBasicService.envType === DesignerEnvType.designer) {
                    this.openCodeViewWithNewMethod.emit({ tsFilePathName: this.tsFilePathName, methodCode: this.methodCode, methodName: this.methodName });
                } else {
                    this.openCodeViewWithNewMethod.emit(this.tsFilePathName);
                }
            } else {
                this.notifyService.error('命令构件创建失败');
            }
        });
    }
}
/**
 * Web构件元数据
 */
export declare class WebComponentMetadata {
    Id: string;
    Code: string;
    Description: string;
    Source: string;
    Operations: Array<Operation>;
    IsCommon: boolean;
    ClassName: string;
    FormCode: string;
    PackageName: string;
    PackageVersion: string;
    Version: number;
}
/** 构件操作 */
export declare class Operation {
    Id: string;
    Code: string;
    Name: string;
    Description: string;
    Parameters: Array<Parameter>;
}
/** 构件操作参数 */
export declare class Parameter {
    Id: string;
    Code: string;
    Name: string;
    Description: string;
    ParameterType: string;
    IsRetVal: boolean;
}
